#pragma once

typedef struct {
	ULONG Type;
	USHORT UsaOffset;
	USHORT UsaCount;
	USN Usn;

} NTFS_RECORD_HEADER, *PNTFS_RECORD_HEADER;

typedef struct {

	NTFS_RECORD_HEADER Ntfs;

	USHORT SequenceNumber;

	USHORT LinkCount;

	USHORT AttributesOffset;

	USHORT Flags; // 0x0001 = InUse, 0x0002 = Directory

	ULONG BytesInUse;

	ULONG BytesAllocated;

	ULONGLONG BaseFileRecord;

	USHORT NextAttributeNumber;

} FILE_RECORD_HEADER, *PFILE_RECORD_HEADER;



typedef enum {

	AttributeStandardInformation = 0x10,

	AttributeAttributeList = 0x20,

	AttributeFileName = 0x30,

	AttributeObjectId = 0x40,

	AttributeSecurityDescriptor = 0x50,

	AttributeVolumeName = 0x60,

	AttributeVolumeInformation = 0x70,

	AttributeData = 0x80,

	AttributeIndexRoot = 0x90,

	AttributeIndexAllocation = 0xA0,

	AttributeBitmap = 0xB0,

	AttributeReparsePoint = 0xC0,

	AttributeEAInformation = 0xD0,

	AttributeEA = 0xE0,

	AttributePropertySet = 0xF0,

	AttributeLoggedUtilityStream = 0x100

} ATTRIBUTE_TYPE, *PATTRIBUTE_TYPE;



typedef struct {

	ATTRIBUTE_TYPE AttributeType;

	ULONG Length;

	BOOLEAN Nonresident;

	UCHAR NameLength;

	USHORT NameOffset;

	USHORT Flags; // 0x0001 = Compressed

	USHORT AttributeNumber;

} ATTRIBUTE, *PATTRIBUTE;



typedef struct {

	ATTRIBUTE Attribute;

	ULONG ValueLength;

	USHORT ValueOffset;

	USHORT Flags; // 0x0001 = Indexed

} RESIDENT_ATTRIBUTE, *PRESIDENT_ATTRIBUTE;



typedef struct {

	ATTRIBUTE Attribute;

	ULONGLONG LowVcn;

	ULONGLONG HighVcn;

	USHORT RunArrayOffset;

	UCHAR CompressionUnit;

	UCHAR AlignmentOrReserved[5];

	ULONGLONG AllocatedSize;

	ULONGLONG DataSize;

	ULONGLONG InitializedSize;

	ULONGLONG CompressedSize; // Only when compressed

} NONRESIDENT_ATTRIBUTE, *PNONRESIDENT_ATTRIBUTE;



typedef struct {

	ULONGLONG CreationTime;

	ULONGLONG ChangeTime;

	ULONGLONG LastWriteTime;

	ULONGLONG LastAccessTime;

	ULONG FileAttributes;

	ULONG AlignmentOrReservedOrUnknown[3];

	ULONG QuotaId; // NTFS 3.0 only

	ULONG SecurityId; // NTFS 3.0 only

	ULONGLONG QuotaCharge; // NTFS 3.0 only

	USN Usn; // NTFS 3.0 only

} STANDARD_INFORMATION, *PSTANDARD_INFORMATION;



typedef struct {

	ATTRIBUTE_TYPE AttributeType;

	USHORT Length;

	UCHAR NameLength;

	UCHAR NameOffset;

	ULONGLONG LowVcn;

	ULONGLONG FileReferenceNumber;

	USHORT AttributeNumber;

	USHORT AlignmentOrReserved[3];

} ATTRIBUTE_LIST, *PATTRIBUTE_LIST;



typedef struct {

	ULONGLONG DirectoryFileReferenceNumber;

	ULONGLONG CreationTime; // Saved when filename last changed

	ULONGLONG ChangeTime; // ditto

	ULONGLONG LastWriteTime; // ditto

	ULONGLONG LastAccessTime; // ditto

	ULONGLONG AllocatedSize; // ditto

	ULONGLONG DataSize; // ditto

	ULONG FileAttributes; // ditto

	ULONG AlignmentOrReserved;

	UCHAR NameLength;

	UCHAR NameType; // 0x01 = Long, 0x02 = Short,  // POSIX 0x00  WIN32 0x01  DOS 0x02  WIN32&DOS 0x03

	WCHAR Name[1];

} FILENAME_ATTRIBUTE, *PFILENAME_ATTRIBUTE;


static ULONG run_length(PUCHAR run)
{
	return (*run & 0xf) + ((*run >> 4) & 0xf) + 1;
}

static LONGLONG run_lcn(PUCHAR run)
{
	LONG i;
	UCHAR n1 = *run & 0xf;
	UCHAR n2 = (*run >> 4) & 0xf;
	LONGLONG lcn = (n2 == 0) ? 0 : (LONGLONG)(((signed char*)run)[n1 + n2]);

	for(i = n1 + n2 - 1; i > n1; i--)
	{
		lcn = (lcn << 8) + run[i];
	}

	return lcn;
}

static ULONGLONG run_count(PUCHAR run)
{
	ULONG i;
	UCHAR n = *run & 0xf;
	ULONGLONG count = 0;

	for(i = n; i > 0; i--)
	{
		count = (count << 8) + run[i];
	}

	return count;
}

static int check_run(ULONGLONG lcn, ULONGLONG length, ULONGLONG total_clusters)
{
	if((lcn < total_clusters) && (lcn + length <= total_clusters))
		return 1;

	return 0;
}
